// Copyright (c) MatrixFramework. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenTelemetry;
using OpenTelemetry.Exporter;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
using Matrix.ServiceCommunication.Options;

namespace Matrix.ServiceCommunication.Monitoring;

/// <summary>
/// Telemetry配置扩展方法
/// </summary>
public static class TelemetryConfiguration
{
    /// <summary>
    /// 配置OpenTelemetry
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddMatrixServiceCommunicationTelemetry(this IServiceCollection services)
    {
        // 注册选项
        services.AddOptions<MonitoringOptions>()
            .BindConfiguration("ServiceCommunication:Monitoring");

        // 注册指标收集器
        services.AddSingleton<IServiceCommunicationMetrics, ServiceCommunicationMetrics>();

        // 配置OpenTelemetry
        services.AddOpenTelemetry()
            .ConfigureResource(builder =>
            {
                builder.AddService("Matrix.ServiceCommunication");
                builder.AddAttributes(new[]
                {
                    new KeyValuePair<string, object>("service.version", "1.0.0"),
                    new KeyValuePair<string, object>("service.language", "dotnet")
                });
            })
            .WithTracing(builder =>
            {
                builder
                    .AddSource("Matrix.ServiceCommunication")
                    .AddHttpClientInstrumentation(options =>
                    {
                        options.SetHttpFlavor = true;
                        options.RecordException = true;
                        options.EnrichWithHttpRequestMessage = (activity, httpRequestMessage) =>
                        {
                            activity.SetTag("http.request.method", httpRequestMessage.Method.Method);
                            activity.SetTag("http.request.uri", httpRequestMessage.RequestUri?.ToString());
                        };
                        options.EnrichWithHttpResponseMessage = (activity, httpResponseMessage) =>
                        {
                            activity.SetTag("http.response.status_code", httpResponseMessage.StatusCode.ToString());
                            activity.SetTag("http.response.status_class", GetStatusClass((int)httpResponseMessage.StatusCode));
                        };
                    })
                    .AddAspNetCoreInstrumentation()
                    .AddOtlpExporter((exporterOptions, metricReaderOptions) =>
                    {
                        // OtlpExporter配置将通过IOptions配置
                    });
            })
            .WithMetrics(builder =>
            {
                builder
                    .AddMeter("Matrix.ServiceCommunication")
                    .AddHttpClientInstrumentation()
                    .AddAspNetCoreInstrumentation()
                    .AddRuntimeInstrumentation()
                    .AddOtlpExporter((exporterOptions, metricReaderOptions) =>
                    {
                        // OtlpExporter配置将通过IOptions配置
                    });
            });

        return services;
    }

    /// <summary>
    /// 配置日志记录
    /// </summary>
    /// <param name="builder">日志构建器</param>
    /// <returns>日志构建器</returns>
    public static ILoggingBuilder AddMatrixServiceCommunicationLogging(this ILoggingBuilder builder)
    {
        builder.AddOpenTelemetry(options =>
        {
            options.IncludeFormattedMessage = true;
            options.IncludeScopes = true;
            options.ParseStateValues = true;
            options.ResourceAttributes = new Dictionary<string, object>
            {
                ["service.name"] = "Matrix.ServiceCommunication",
                ["service.version"] = "1.0.0"
            };
        });

        return builder;
    }

    private static string GetStatusClass(int statusCode)
    {
        return statusCode switch
        {
            >= 200 and < 300 => "2xx",
            >= 300 and < 400 => "3xx",
            >= 400 and < 500 => "4xx",
            >= 500 => "5xx",
            _ => "unknown"
        };
    }
}

/// <summary>
/// OpenTelemetry配置选项
/// </summary>
public class OpenTelemetryOptions
{
    /// <summary>
    /// 启用链路追踪
    /// </summary>
    public bool EnableTracing { get; set; } = true;

    /// <summary>
    /// 启用指标收集
    /// </summary>
    public bool EnableMetrics { get; set; } = true;

    /// <summary>
    /// 启用日志收集
    /// </summary>
    public bool EnableLogging { get; set; } = true;

    /// <summary>
    /// OTLP导出端点
    /// </summary>
    public string? OtlpEndpoint { get; set; }

    /// <summary>
    /// OTLP导出器Headers
    /// </summary>
    public Dictionary<string, string>? OtlpHeaders { get; set; }

    /// <summary>
    /// 服务名称
    /// </summary>
    public string ServiceName { get; set; } = "Matrix.ServiceCommunication";

    /// <summary>
    /// 服务版本
    /// </summary>
    public string ServiceVersion { get; set; } = "1.0.0";

    /// <summary>
    /// 采样率 (0.0 - 1.0)
    /// </summary>
    public double SamplingRatio { get; set; } = 1.0;
}

/// <summary>
/// OpenTelemetry扩展配置方法
/// </summary>
public static class OpenTelemetryExtensions
{
    /// <summary>
    /// 配置OtlpExporter
    /// </summary>
    /// <param name="builder">构建器</param>
    /// <param name="options">配置选项</param>
    public static void ConfigureOtlpExporter(this MeterProviderBuilder builder, OpenTelemetryOptions options)
    {
        if (string.IsNullOrEmpty(options.OtlpEndpoint)) return;

        builder.AddOtlpExporter(otlpOptions =>
        {
            otlpOptions.Endpoint = new Uri(options.OtlpEndpoint);

            if (options.OtlpHeaders != null)
            {
                foreach (var header in options.OtlpHeaders)
                {
                    otlpOptions.Headers.Add(header.Key, header.Value);
                }
            }

            otlpOptions.ExportProcessorType = ExportProcessorType.Batch;
            otlpOptions.BatchExportProcessorOptions = new()
            {
                MaxExportBatchSize = 512,
                MaxQueueSize = 2048,
                MaxExportTimeoutMilliseconds = 30000,
                ScheduledDelayMilliseconds = 5000
            };
        });
    }

    /// <summary>
    /// 配置OtlpExporter
    /// </summary>
    /// <param name="builder">构建器</param>
    /// <param name="options">配置选项</param>
    public static void ConfigureOtlpExporter(this TracerProviderBuilder builder, OpenTelemetryOptions options)
    {
        if (string.IsNullOrEmpty(options.OtlpEndpoint)) return;

        builder.AddOtlpExporter(otlpOptions =>
        {
            otlpOptions.Endpoint = new Uri(options.OtlpEndpoint);

            if (options.OtlpHeaders != null)
            {
                foreach (var header in options.OtlpHeaders)
                {
                    otlpOptions.Headers.Add(header.Key, header.Value);
                }
            }

            otlpOptions.ExportProcessorType = ExportProcessorType.Batch;
            otlpOptions.BatchExportProcessorOptions = new()
            {
                MaxExportBatchSize = 512,
                MaxQueueSize = 2048,
                MaxExportTimeoutMilliseconds = 30000,
                ScheduledDelayMilliseconds = 5000
            };
        });
    }

    /// <summary>
    /// 配置采样
    /// </summary>
    /// <param name="builder">构建器</param>
    /// <param name="samplingRatio">采样率</param>
    public static void ConfigureSampling(this TracerProviderBuilder builder, double samplingRatio)
    {
        builder.SetSampler(new ParentBasedSampler(new TraceIdRatioBasedSampler(samplingRatio)));
    }
}